package com.ikas.ai.server.module.steady.service;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.ikas.ai.consts.MachineAndWorkConditionConst;
import com.ikas.ai.consts.TableDictConsts;
import com.ikas.ai.enums.MeteTypeEnum;
import com.ikas.ai.model.PageQuery;
import com.ikas.ai.server.error.BusinessException;
import com.ikas.ai.server.module.alarm.enums.SolvedEnum;
import com.ikas.ai.server.module.alarm.model.enums.AlarmType;
import com.ikas.ai.server.module.alarm.service.AlarmCacheService;
import com.ikas.ai.server.module.data.dao.MeteDao;
import com.ikas.ai.server.module.data.model.BaseMete;
import com.ikas.ai.server.module.data.model.tdengine.RealDataHis;
import com.ikas.ai.server.module.data.service.DataService;
import com.ikas.ai.server.module.data.tdDao.DataHisTdMapper;
import com.ikas.ai.server.module.steady.dao.SteadyAlarmDataMapper;
import com.ikas.ai.server.module.steady.dao.SteadyMonitorMeteMapper;
import com.ikas.ai.server.module.steady.model.dto.SteadyAlarmCacheDTO;
import com.ikas.ai.server.module.steady.model.dto.StyAlarmDataPageDto;
import com.ikas.ai.server.module.steady.model.dto.StyAlarmDataQueryDto;
import com.ikas.ai.server.module.steady.model.dto.StyMonMeteQueryDto;
import com.ikas.ai.server.module.steady.model.po.SteadyAlarmData;
import com.ikas.ai.server.module.steady.model.po.SteadyMonitorMete;
import com.ikas.ai.server.module.steady.model.vo.StyAlarmDataVo;
import com.ikas.ai.server.security.UserContextHolder;
import com.ikas.ai.utils.PageExUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 稳态预警数据表 服务实现类
 * </p>
 *
 * @author wuyf
 * @since 2023-12-13
 */
@Service
@Slf4j
public class SteadyAlarmDataService extends ServiceImpl<SteadyAlarmDataMapper, SteadyAlarmData> {

    @Resource
    SteadyMonitorMeteService steadyMonitorMeteService;
    @Resource
    SteadyAlarmDataMapper steadyAlarmDataMapper;
    @Resource
    AlarmCacheService alarmCacheService;
    @Autowired
    DataService dataService;
    @Resource
    SteadyMonitorMeteMapper steadyMonitorMeteMapper;
    @Autowired
    DataHisTdMapper dataHisTdMapper;
    @Resource
    MeteDao meteDao;


    public PageInfo<StyAlarmDataVo> pageStyAlarmData(StyAlarmDataQueryDto queryDto, PageQuery page) {
        PageExUtil.configPageHelper(page);
        List<StyAlarmDataPageDto> list = steadyAlarmDataMapper.list(queryDto);
        return PageExUtil.convert(new PageInfo<>(list), this::coverDtoToStyAlarmDataVo);
    }


    public List<StyAlarmDataVo> listStyAlarmData(StyAlarmDataQueryDto queryDto) {
        StyMonMeteQueryDto styMonMeteQueryDto = BeanUtil.copyProperties(queryDto, StyMonMeteQueryDto.class);
        List<SteadyMonitorMete> styMonMetes = steadyMonitorMeteService.listStyMonMeteNoVo(styMonMeteQueryDto);
        List<Long> monitorMeteIds = styMonMetes.stream().map(SteadyMonitorMete::getId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(monitorMeteIds)) {
            queryDto.setMonitorMeteIds(monitorMeteIds);
            List<SteadyAlarmData> list = queryWrapperList(queryDto);
            List<StyAlarmDataVo> alarmDataVoList = list.stream().map(this::coverToStyAlarmDataVo).collect(Collectors.toList());
            alarmDataVoList.forEach(i -> {
                String iMachineNo = i.getMachineNo();
                switch (iMachineNo) {
                    case MachineAndWorkConditionConst.MACHINE_01_NO:
                        iMachineNo = MachineAndWorkConditionConst.MACHINE_01_ALIAS;
                        break;
                    case MachineAndWorkConditionConst.MACHINE_02_NO:
                        iMachineNo = MachineAndWorkConditionConst.MACHINE_02_ALIAS;
                        break;
                    case MachineAndWorkConditionConst.MACHINE_03_NO:
                        iMachineNo = MachineAndWorkConditionConst.MACHINE_03_ALIAS;
                        break;
                    case MachineAndWorkConditionConst.MACHINE_04_NO:
                        iMachineNo = MachineAndWorkConditionConst.MACHINE_04_ALIAS;
                        break;
                }
                i.setMachineNo(iMachineNo);
            });
        }
        return Collections.emptyList();
    }


    @Transactional(rollbackFor = Exception.class)
    public boolean solved(Long id) {
        SteadyAlarmData alarmData = Optional.ofNullable(
                this.getById(id)
        ).orElseThrow(() -> new BusinessException("没找到可消缺的数据"));

        if (SolvedEnum.SOLVED.getSolved().equals(alarmData.getSolved())) {
            throw new BusinessException("当前数据已消缺，不能重复");
        }
        alarmData.setSolved(SolvedEnum.SOLVED.getSolved());
        alarmData.setSolveTime(new Date());
        alarmData.setSolveUser(UserContextHolder.getTokenUser().getAccount());
        alarmData.setUpdateTime(new Date());
        boolean b = this.updateById(alarmData);
        //更新redis
        List<SteadyAlarmCacheDTO> list = steadyAlarmDataMapper.selectCountBySolved(SolvedEnum.UN_SOLVED.getSolved());
        Map<String, List<SteadyAlarmCacheDTO>> map = list.stream().filter(i -> StringUtils.isNotBlank(i.getMachineNo())).collect(Collectors.groupingBy(SteadyAlarmCacheDTO::getMachineNo));
        map.forEach((k, v) -> alarmCacheService.updateAlarm(AlarmType.STEADY_ALARM, k, v.size()));
        return b;
    }


    public List<RealDataHis> trend(Long id) {
        SteadyAlarmData steadyAlarmData = Optional.ofNullable(steadyAlarmDataMapper.selectById(id))
                .orElseThrow(() -> new BusinessException("不存在该记录"));
        SteadyMonitorMete steadyMonitorMete = Optional.ofNullable(
                steadyMonitorMeteMapper.selectById(steadyAlarmData.getMonitorMeteId())
        ).orElseThrow(() -> new BusinessException("不存在该测点"));

        LambdaQueryChainWrapper<BaseMete> wrapper = new LambdaQueryChainWrapper<>(meteDao);
        BaseMete baseMete = wrapper.eq(BaseMete::getMeteId, steadyMonitorMete.getMeteId())
                .eq(BaseMete::getMeteType, MeteTypeEnum.YC.getNum())
                .one();
        if (Objects.isNull(baseMete)) {
            throw new BusinessException("该测点不存在");
        }
        List<RealDataHis> realDataHis = dataHisTdMapper.selectByTableNameAndMeteId(TableDictConsts.DATA_HIS_PREFIX_YC + baseMete.getMeteId(), baseMete.getMeteId(), steadyAlarmData.getSteadyStartTime(), steadyAlarmData.getAlarmTime());
        realDataHis = realDataHis.stream().sorted(Comparator.comparingLong(i -> i.getIdTime().getTime())).collect(Collectors.toList());
        return realDataHis;
    }


    private List<SteadyAlarmData> queryWrapperList(StyAlarmDataQueryDto queryDto) {
        LambdaQueryWrapper<SteadyAlarmData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(SteadyAlarmData::getMonitorMeteId, queryDto.getMonitorMeteIds());
        queryWrapper.eq(ObjectUtils.isNotEmpty(queryDto.getSteadyType()), SteadyAlarmData::getSteadyType, queryDto.getSteadyType());
        queryWrapper.eq(ObjectUtils.isNotEmpty(queryDto.getSolved()), SteadyAlarmData::getSolved, queryDto.getSolved());
        queryWrapper.ge(StringUtils.isNotBlank(queryDto.getStartAlarmTime()), SteadyAlarmData::getAlarmTime, queryDto.getStartAlarmTime());
        queryWrapper.le(StringUtils.isNotBlank(queryDto.getEndAlarmTime()), SteadyAlarmData::getAlarmTime, queryDto.getEndAlarmTime());
        queryWrapper.orderByDesc(SteadyAlarmData::getAlarmTime);
        return this.list(queryWrapper);
    }

    /**
     * 实体转VO
     *
     * @param styAlarmData 实体类
     * @return vo of StyMonMete
     */
    private StyAlarmDataVo coverToStyAlarmDataVo(SteadyAlarmData styAlarmData) {
        return BeanUtil.copyProperties(styAlarmData, StyAlarmDataVo.class);
    }

    private StyAlarmDataVo coverDtoToStyAlarmDataVo(StyAlarmDataPageDto styAlarmData) {
        BigDecimal trendChangeValue = styAlarmData.getTrendChangeValue();
        if (0.0 == trendChangeValue.doubleValue()) {
            styAlarmData.setTrendChangeValue(null);
        }
        return BeanUtil.copyProperties(styAlarmData, StyAlarmDataVo.class);
    }

    public PageInfo<RealDataHis> trendPage(Long id, PageQuery pageQuery) {
        SteadyAlarmData steadyAlarmData = Optional.ofNullable(steadyAlarmDataMapper.selectById(id))
                .orElseThrow(() -> new BusinessException("不存在该记录"));
        SteadyMonitorMete steadyMonitorMete = Optional.ofNullable(
                steadyMonitorMeteMapper.selectById(steadyAlarmData.getMonitorMeteId())
        ).orElseThrow(() -> new BusinessException("不存在该测点"));

        LambdaQueryChainWrapper<BaseMete> wrapper = new LambdaQueryChainWrapper<>(meteDao);
        BaseMete baseMete = wrapper.eq(BaseMete::getMeteId, steadyMonitorMete.getMeteId())
                .eq(BaseMete::getMeteType, MeteTypeEnum.YC.getNum())
                .one();
        if (Objects.isNull(baseMete)) {
            throw new BusinessException("该测点不存在");
        }
        pageQuery.setSortBy("idtime");
        return dataService.selectTrendData(baseMete, steadyAlarmData, pageQuery);
    }
}
